package com.lintf.distributed.transaction.inventory.config;

import com.lintf.distributed.transaction.inventory.exception.RetryStatisticsException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义重试监听器，记录重试统计信息
 */
@Slf4j
public class RetryStatisticsListener implements RetryListener {
    private static final String RETRY_COUNT_ATTRIBUTE_KEY = "retry_count";
    private static final String RETRY_TIMES_ATTRIBUTE_KEY = "retry_times";

    @Override
    public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
        log.debug("[RetryStatisticsListener]开始重试");
        context.setAttribute(RETRY_COUNT_ATTRIBUTE_KEY, 0);
        context.setAttribute(RETRY_TIMES_ATTRIBUTE_KEY, new ArrayList<Long>());
        return true;
    }

    @Override
    public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        List<Long> retryTimes = getAttribute(context, RETRY_TIMES_ATTRIBUTE_KEY, List.class);
        if (retryTimes != null) {
            retryTimes.add(System.currentTimeMillis());
        }

        Integer retryCount = getAttribute(context, RETRY_COUNT_ATTRIBUTE_KEY, Integer.class);
        int value = 0;
        if (retryCount != null) {
            value = retryCount + 1;
            context.setAttribute(RETRY_COUNT_ATTRIBUTE_KEY, value);
        }
        log.warn("[RetryStatisticsListener]重试失败: 第[{}]重试, 错误信息：{}", value, throwable.getMessage());
    }

    @Override
    public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        int attemptCount = context.getRetryCount();
        if (attemptCount > 0) {
            if (throwable == null) {
                log.info("[RetryStatisticsListener]重试成功: 共尝试 {} 次", attemptCount);
            } else {
                log.error("[RetryStatisticsListener]重试失败: 共尝试 {} 次", attemptCount, throwable);
            }
        }

        if (throwable != null) {
            Integer retryCount = getAttribute(context, RETRY_COUNT_ATTRIBUTE_KEY, Integer.class);
            List<Long> retryTimes = getAttribute(context, RETRY_TIMES_ATTRIBUTE_KEY, List.class);

            if (retryCount != null && retryTimes != null) {
                // 避免重复添加
                boolean alreadyAdded = false;
                for (Throwable t : throwable.getSuppressed()) {
                    if (t instanceof RetryStatisticsException) {
                        alreadyAdded = true;
                        break;
                    }
                }
                if (!alreadyAdded) {
                    throwable.addSuppressed(new RetryStatisticsException(retryCount, retryTimes));
                }
            }
        }
    }

    /**
     * 安全地从 RetryContext 获取属性并做类型检查
     */
    @SuppressWarnings("unchecked")
    private <V> V getAttribute(RetryContext context, String key, Class<V> expectedType) {
        Object value = context.getAttribute(key);
        if (value != null && expectedType.isAssignableFrom(value.getClass())) {
            return (V) value;
        } else {
            log.warn("[RetryStatisticsListener]无法从 RetryContext 获取属性：{}，类型不匹配或不存在", key);
            return null;
        }
    }
}
